package com.fast.user.service;

import com.fast.user.controller.StatusCode;
import com.fast.user.domain.User;
import com.fast.user.domain.UserBalanceTcc;
import com.fast.user.domain.type.TccStatus;
import com.fast.user.exception.ReservationExpireException;
import com.fast.user.persistence.UserBalanceTccMapper;
import com.fast.user.persistence.UserMapper;
import com.google.common.base.Preconditions;
import com.wmm.common.Shift;
import com.wmm.common.persistence.CrudMapper;
import com.wmm.common.service.CrudServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.OffsetDateTime;

@Service
public class UserBalanceTccService extends CrudServiceImpl<UserBalanceTcc> {
    @Autowired
    public UserBalanceTccService(CrudMapper<UserBalanceTcc> mapper) {
        super(mapper);
    }

    @Autowired
    private UserService userService;
    @Autowired
    private UserMapper userMapper;
    @Autowired
    private UserBalanceTccMapper userBalanceTccMapper;

    public UserBalanceTcc trying(Long userId, Long amount) {
        return trying(userId,amount,15);

    }

    private UserBalanceTcc trying(Long userId, Long amount, long expireSeconds) {
        Preconditions.checkNotNull(userId);
        Preconditions.checkNotNull(amount);
        Preconditions.checkArgument(expireSeconds > 0);
        final User user = userService.find(userId);
        if(user == null) {
            Shift.fatal(StatusCode.USER_NOT_EXISTS);
        }
        return trying(user,amount,expireSeconds);
    }

    @Transactional(rollbackFor = Exception.class)
    public UserBalanceTcc trying(User user,Long amount,long expireSeconds) {
        Preconditions.checkNotNull(user);
        Preconditions.checkNotNull(amount);
        Preconditions.checkArgument(expireSeconds > 0);
        final int isLocks = userMapper.consumeBalance(user.getId(),amount);
        if(isLocks == 0) {
            Shift.fatal(StatusCode.INSUFFICIENT_BALANCE);
        }
        final UserBalanceTcc tcc = new UserBalanceTcc();
        tcc.setAmount(amount);
        tcc.setExpireTime(OffsetDateTime.now().plusSeconds(expireSeconds));
        tcc.setStatus(TccStatus.TRY);
        tcc.setUserId(user.getId());
        super.persistNonNullProperties(tcc);
        return tcc;
    }

    /** 执行confirm */
    public void confirmReservation(Long reservationId) {
        Preconditions.checkNotNull(reservationId);
        final UserBalanceTcc tcc = find(reservationId);
        if(tcc == null) {
            //说明已被补偿或不存在或过期
            throw new ReservationExpireException("resource `" + reservationId + "` has been cancelled or does not exists at all");
        }
        //确认如果是try阶段
        if(tcc.getStatus() == TccStatus.TRY) {
            final int isSuccessful = userBalanceTccMapper.updateToConfirmationById(reservationId);
            if(isSuccessful == 0) {
                throw new ReservationExpireException("resource `" + reservationId + "` has been cancelled");
            }
        }
    }
}
